package fem2.observer;

import java.io.IOException;
import java.util.ArrayList;

import fem2.Debugger;
import fem2.Element;
import fem2.MaterialModel;
import fem2.Model;
import fem2.Variable;
import fem2.element.StructuralElement;
import fem2.enu.VariableName;
import fem2.material.IsotropicDamageMM;
import fem2.material.LemaitreDamageMM;
import fem2.material.LemaitreDamageMM2;
import fem2.material.StVenantKirchhoffMM;

public class GidDamageObserver extends GidStructuralObserver {

	public GidDamageObserver(Model m, TimeStepObserver o, String projectDir, String projectName) {
		super(m, o, projectDir, projectName);
	}

	public GidDamageObserver(Model m, TimeStepObserver o, String projectDir, String projectName,
			String fileName) {
		super(m, o, projectDir, projectName, fileName);
	}

	@Override
	public void fireStarted() {
	}

	@Override
	public void fireTimeStepStarted() {
	}

	@Override
	public void fireIterationStarted() {
	}

	@Override
	public void fireIterationFinished() {
	}

	@Override
	public void fireTimeStepFinished() {
		int ne = m.countElements();

		/*
		 * gid section. enabled when gidpost!=null
		 */
		if (gidPost != null) {
			for (String elemType : m.getElementTypes()) {
				/*
				 * prepare data
				 */
				ArrayList<Integer> elemIds = new ArrayList<Integer>();
				int ng = 0;
				for (int i = 0; i < ne; i++) {
					Element e = m.getElement(i);
					if (e.getElemType().equals(elemType)) {
						elemIds.add(e.getId());
						if (ng == 0) {
							ng = e.getNumIntegrationPoints();
						} else if (e.getNumIntegrationPoints() != ng) {
							throw new Error(
									"number of Gauss points must be the same for all element of the same type");
						}
					}
				}

				String DamageVarName = "DAMAGE_VARIABLE";

				double timeStep = timeStepObserver.getCurrentTimeStep();

				int[] elementIds = new int[elemIds.size()];
				double[][] damageValues = new double[elemIds.size()][ng];
				for (int i = 0; i < elemIds.size(); i++) {
					elementIds[i] = elemIds.get(i);
					StructuralElement se = (StructuralElement) m.getElement(elementIds[i] - 1);

					ArrayList<Variable> vars;

					MaterialModel mm = se.getMaterialModel();
					if (mm instanceof IsotropicDamageMM) {
						vars = ((IsotropicDamageMM) mm).getVariables(se);
					} else if (mm instanceof LemaitreDamageMM) {
						vars = ((LemaitreDamageMM) mm).getVariables(se);
					} else if (mm instanceof LemaitreDamageMM2) {
						vars = ((LemaitreDamageMM2) mm).getVariables(se);
					} else if (mm instanceof StVenantKirchhoffMM) {
						/*
						 * this code is to allow for virgin material combine
						 * with damage still allow for new damage model to be
						 * implemented
						 */
						vars = null;
					} else {
						throw new Error("this material model is not supported");
					}

					if (vars == null) {
						Debugger.warn("the associated material model is not of damage type, setting damage to 0");

						for (int k = 0; k < ng; k++) {
							damageValues[i][k] = 0;
						}

					} else {
						for (int k = 0; k < ng; k++) {
							damageValues[i][k] = vars.get(k).getScalarVariable(VariableName.DAMAGE)
									.getValue();
						}
					}
				}
				/*
				 * write block of values for damage variable
				 */
				try {
					gidPost.writeMesh(m, timeStep);
					String groupName = "damage_gp_" + elemType;
					gidPost.writeGausspointScalarResult(DamageVarName, groupName, elemType,
							elementIds, damageValues, timeStep);
				} catch (IOException e) {
					throw new Error("Write failed: " + e.getMessage());
				}
			}
		}
	}

	@Override
	public void fireFinished() {
	}

}
